<!doctype html>

<html>

<head>
  <meta charset="UTF-8">
  <title>iron-list test</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">

  <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
  <script src="../../web-component-tester/browser.js"></script>
  <link rel="import" href="../../test-fixture/test-fixture.html">

  <link rel="import" href="helpers.html">
  <link rel="import" href="../vaadin-grid.html">
  <link rel="import" href="../vaadin-grid-filter.html">
  <link rel="import" href="../vaadin-grid-sorter.html">
</head>

<body>

  <test-fixture id="default">
    <template>
      <vaadin-grid>
        <vaadin-grid-column>
          <template class="header">First</template>
          <template>[[item.name.first]]</template>
        </vaadin-grid-column>
        <vaadin-grid-column>
          <template class="header">Last</template>
          <template>[[item.name.last]]</template>
        </vaadin-grid-column>
      </vaadin-grid>
    </template>
  </test-fixture>

  <test-fixture id="invalid-path">
    <template>
      <vaadin-grid>
        <vaadin-grid-column>
          <template class="header">
            <vaadin-grid-sorter>
              Sorter with invalid path
            </vaadin-grid-sorter>
          </template>
          <template>[[item.name.first]]</template>
        </vaadin-grid-column>

        <vaadin-grid-column>
          <template class="header">
            <vaadin-grid-filter value="foo">
            </vaadin-grid-filter>
          </template>
          <template>[[item.name.last]]</template>
        </vaadin-grid-column>
      </vaadin-grid>
    </template>
  </test-fixture>

  <script>
    describe('array data provider', () => {
      let grid, body;

      function getContent(row, column) {
        return getCellContent(getCell(row, column)).innerText;
      }

      function getCell(row, column) {
        return getRowCells(getRows(body)[row])[column];
      }

      beforeEach(done => {
        grid = fixture('default');
        grid.items = [{
          name: {
            first: 'foo',
            last: 'bar'
          }
        }, {
          name: {
            first: 'baz',
            last: 'qux'
          }
        }];
        flushGrid(grid);
        body = grid.$.items;
        animationFrameFlush(done);
      });

      it('should have right amount of data', () => {
        const bodyRows = getRows(body);
        expect(bodyRows).to.have.length(2);
      });

      it('should work after initialized with empty items', () => {
        grid = fixture('default');
        grid.items = [];
        grid.items = [0];
        flushGrid(grid);
        expect(getRows(grid.$.items)).to.have.length(1);
      });

      it('should have the right data', () => {
        expect(getContent(0, 0)).to.equal('foo');
        expect(getContent(1, 0)).to.equal('baz');
      });

      it('should be observed for shift', () => {
        grid.unshift('items', {
          name: {
            first: 'a',
            last: 'b'
          }
        });
        expect(grid.size).to.equal(3);
        expect(getContent(0, 0)).to.equal('a');
      });

      it('should be observed for mutation', () => {
        grid.set('items.0.name.first', 'new');
        expect(getContent(0, 0)).to.equal('new');
      });

      it('should handle null', () => {
        grid.items = null;
        expect(grid.size).to.equal(0);
      });

      it('should set array data provider', () => {
        expect(grid.dataProvider).to.equal(grid._arrayDataProvider);
      });

      it('should not override custom data provider', () => {
        const ds = grid.dataProvider = () => {};
        grid.items = [1, 2, 3];
        expect(grid.dataProvider).to.equal(ds);
      });

      it('should handle new array of same length', () => {
        grid.items = [{
          name: {
            first: 'a'
          }
        }, {
          name: {
            first: 'b'
          }
        }];
        expect(getContent(0, 0)).to.equal('a');
      });
    });

    describe('invalid paths', () => {
      let grid;

      beforeEach(() => {
        grid = fixture('invalid-path');

        grid.items = [{
          name: {
            first: 'foo',
            last: 'bar'
          }
        }];
        flushGrid(grid);
      });

      describe('invalid sorters paths', () => {
        let sorter;

        beforeEach(() => sorter = grid.querySelector('vaadin-grid-sorter'));

        it('should warn about invalid path with undefined parent property', () => {
          const _warn = console.warn;
          const spy = console.warn = sinon.spy();

          sorter.path = 'foo.bar';
          click(sorter);
          console.warn = _warn;

          expect(spy.called).to.be.true;
        });

        it('should not warn about undefined values with defined parent property', () => {
          const _warn = console.warn;
          const spy = console.warn = sinon.spy();

          sorter.path = 'name.foo';
          click(sorter);
          console.warn = _warn;

          expect(spy.called).to.be.false;
        });

        it('should not warn about invalid path without dots', () => {
          const _warn = console.warn;
          const spy = console.warn = sinon.spy();

          sorter.path = 'foobar';
          click(sorter);
          console.warn = _warn;

          expect(spy.called).to.be.false;
        });

        it('should not warn about undefined values with defined parent property (long path)', () => {
          grid.items = [{
            name: {
              last: {
                foo: 'foo'
              }
            }
          }];

          const _warn = console.warn;
          const spy = console.warn = sinon.spy();

          sorter.path = 'name.last.foo';
          click(sorter);
          console.warn = _warn;

          expect(spy.called).to.be.false;
        });
      });

      describe('invalid filters paths', () => {
        let filter;

        beforeEach(done => {
          filter = grid.querySelector('vaadin-grid-filter');
          listenOnce(grid, 'filter-changed', e => {
            done();
          });
          filter.path = '';
        });

        it('should warn about invalid path with undefined parent property', done => {
          const _warn = console.warn;
          const spy = console.warn = sinon.spy();

          listenOnce(filter, 'filter-changed', e => {
            setTimeout(() => {
              console.warn = _warn;
              expect(spy.called).to.be.true;
              done();
            });
          });

          filter.path = 'foo.bar';
        });

        it('should not warn about undefined values with defined parent property', done => {
          const _warn = console.warn;
          const spy = console.warn = sinon.spy();

          listenOnce(filter, 'filter-changed', e => {
            setTimeout(() => {
              console.warn = _warn;
              expect(spy.called).to.be.false;
              done();
            });
          });

          filter.path = 'name.foo';
        });

        it('should not warn about invalid path without dots', done => {
          const _warn = console.warn;
          const spy = console.warn = sinon.spy();

          listenOnce(filter, 'filter-changed', e => {
            setTimeout(() => {
              console.warn = _warn;
              expect(spy.called).to.be.false;
              done();
            });
          });

          filter.path = 'foobar';
        });
      });
    });
  </script>

</body>

</html>
